package com.hllxd.hism.star.basic.service.service.rock;

import com.hllxd.hism.star.basic.service.beans.ScoreRuleCheckInfo;
import com.hllxd.hism.star.basic.service.beans.TaskRelationBO;
import com.hllxd.hism.star.basic.service.beans.TaskScoreBO;
import com.hllxd.hism.star.basic.service.dao.mapper.mis.TaskInfoMapper;
import com.hllxd.hism.star.basic.service.model.rock.TaskExecuteLog;
import com.hllxd.hism.star.basic.service.model.rock.TaskInfo;
import com.hllxd.hism.star.basic.service.model.rock.TaskRelation;
import com.hllxd.hism.star.basic.service.util.DateUtil;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author wuguangxi
 * @Description
 * @Date 2024/3/14 11:11
 */
@Service
public class TaskServiceImpl implements TaskService {

    @Autowired
    private TaskRelationService taskRelationService;
    @Autowired
    private TaskExecuteLogService taskExecuteLogService;
    @Autowired
    private TaskInfoMapper taskInfoMapper;

    private List<Integer> MANUAL_RUN_TYPE = Arrays.asList(2, 3, 6, 7, 8);


    @Override
    public List<TaskRelationBO> findByTaskIdOrNaneAndType(String task, String relationType) {
        if(Strings.isEmpty(task) || Strings.isEmpty(relationType)){
            return Collections.emptyList();
        }
        String taskId;
        TaskInfo taskInfo = getTask(task);
        if(taskInfo == null){
            return Collections.emptyList();
        }else {
            taskId = taskInfo.getTaskId();
        }

        List<TaskRelationBO> resultList = new ArrayList<>();
        Set<String> taskIdSet = new HashSet<>();
        getNextLvlTask(taskId, relationType, "", 0, resultList, taskIdSet, getRelationMap(relationType), getTaskInfoMap());
        fillOtherDeptName(resultList);
        resultList.sort(Comparator.comparing(TaskRelationBO::getLvl));
        return resultList;
    }

    @Override
    public TaskScoreBO getTaskScore(String task) {
        TaskInfo taskInfo = getTask(task);
        if(taskInfo == null){
            return null;
        }
        TaskScoreBO scoreBO = new TaskScoreBO();
        scoreBO.setTaskId(taskInfo.getTaskId());
        scoreBO.setTaskName(taskInfo.getTaskName());
        Map<String, TaskInfo> taskInfoMap = getTaskInfoMap();
        // 计算安全分
        calcSecurityScore(taskInfo, scoreBO, taskInfoMap);

        // 计算重要分
        calcImportantScore(taskInfo, scoreBO);
        return scoreBO;
    }

    /**
     * 计算安全分
     * @param taskInfo
     * @param scoreBO
     * @param taskInfoMap
     */
    private void calcSecurityScore(TaskInfo taskInfo, TaskScoreBO scoreBO, Map<String, TaskInfo> taskInfoMap){

        // 查询上级三层依赖任务
        List<TaskRelationBO> relationBOS = findByTaskIdOrNaneAndType(taskInfo.getTaskId(), "up");
        List<String> taskIds = relationBOS.stream().map(TaskRelationBO::getTaskId).collect(Collectors.toList());
        Map<String, List<TaskExecuteLog>> executeLogMap = taskExecuteLogService.findExecuteLogMapByTaskIds(taskIds);
        // 过滤掉手动运行的
        executeLogMap.forEach((id, list) -> {
            list.removeIf(log -> MANUAL_RUN_TYPE.contains(log.getJobExecuteType()));
        });

        relationBOS.removeIf(relationBO -> relationBO.getLvl() > 3);
        // 对单个任务计算扣分项
        // 当前节点扣分项
        List<ScoreRuleCheckInfo> checkInfos = new ArrayList<>();
        checkInfos.add(checkRootTaskSecurityScore(taskInfo, executeLogMap));
        // 上游节点扣分项
        relationBOS.forEach(relationBO -> checkInfos.add(checkOneTaskSecurityScore(relationBO, taskInfoMap, executeLogMap)));

        // 汇总结果
        checkInfos.removeIf(checkInfo -> checkInfo == null || checkInfo.getScore() == 0);
        int score = 100 - checkInfos.stream().mapToInt(ScoreRuleCheckInfo::getScore).sum();
        if(score < 0){
            score = 0;
        }
        scoreBO.setSecurityScore(score);
        scoreBO.setSecurityDetailList(checkInfos.stream().map(ScoreRuleCheckInfo::getMsg).collect(Collectors.toList()));
    }

    /**
     * 计算重要分
     * @param taskInfo
     * @param scoreBO
     */
    private void calcImportantScore(TaskInfo taskInfo, TaskScoreBO scoreBO){
        // 查询下级三层依赖任务
        List<TaskRelationBO> relationBOS = findByTaskIdOrNaneAndType(taskInfo.getTaskId(), "down");
        relationBOS.removeIf(relationBO -> relationBO.getLvl() > 5);

        // 下游节点分数
        List<ScoreRuleCheckInfo> checkInfos = new ArrayList<>();
        relationBOS.forEach(relationBO -> checkInfos.add(checkOneTaskImportantScore(relationBO)));
        checkInfos.removeIf(checkInfo -> checkInfo == null || checkInfo.getScore() == 0);
        int score = checkInfos.stream().mapToInt(ScoreRuleCheckInfo::getScore).sum();
        scoreBO.setImportantScore(score);
        scoreBO.setImportantDetailList(checkInfos.stream().map(ScoreRuleCheckInfo::getMsg).collect(Collectors.toList()));
    }

    /**
     * 计算单个任务重要分
     * @param relationBO
     * @return
     */
    private ScoreRuleCheckInfo checkOneTaskImportantScore(TaskRelationBO relationBO){
        ScoreRuleCheckInfo scoreRuleCheckInfo = new ScoreRuleCheckInfo();
        scoreRuleCheckInfo.setScore(0);
        // 依赖层级 < 3
        if(relationBO.getLvl() <= 3){
            switch (relationBO.getImportantLvl()){
                case "1":
                    scoreRuleCheckInfo.setScore(9);
                    scoreRuleCheckInfo.setMsg(relationBO.getTaskName() + "：依赖层级为" + relationBO.getLvl() + ",重要等级为P0");
                    break;
                case "2":
                    scoreRuleCheckInfo.setScore(5);
                    scoreRuleCheckInfo.setMsg(relationBO.getTaskName() + "：依赖层级为" + relationBO.getLvl() + ",重要等级为P1");
                    break;
                case "3":
                    scoreRuleCheckInfo.setScore(2);
                    scoreRuleCheckInfo.setMsg(relationBO.getTaskName() + "：依赖层级为" + relationBO.getLvl() + ",重要等级为P2");
                    break;
            }
        }else {
            // 依赖层级 > 3 且为P0或P1任务
            switch (relationBO.getImportantLvl()){
                case "1":
                    scoreRuleCheckInfo.setMsg(relationBO.getTaskName() + "：依赖层级为" + relationBO.getLvl() + ",重要等级为P0");
                    scoreRuleCheckInfo.setScore(5);
                    break;
                case "2":
                    scoreRuleCheckInfo.setMsg(relationBO.getTaskName() + "：依赖层级为" + relationBO.getLvl() + ",重要等级为P1");
                    scoreRuleCheckInfo.setScore(5);
                    break;
            }
        }
        return scoreRuleCheckInfo;
    }

    /**
     * 校验单个任务安全分
     * @param relationBO
     * @param taskInfoMap
     * @return
     */
    private ScoreRuleCheckInfo checkOneTaskSecurityScore(TaskRelationBO relationBO, Map<String, TaskInfo> taskInfoMap, Map<String, List<TaskExecuteLog>> logMap){
        ScoreRuleCheckInfo scoreRuleCheckInfo = new ScoreRuleCheckInfo();
        scoreRuleCheckInfo.setScore(0);
        String lvl = relationBO.getImportantLvl();
        List<TaskExecuteLog> executeLogList = logMap.get(relationBO.getTaskId());
        // 是否有配置重要级别
        if(Strings.isBlank(lvl) || "-1".equals(lvl)){
            scoreRuleCheckInfo.setScore(5);
            scoreRuleCheckInfo.setMsg(relationBO.getTaskName() + "：未配置重要级别");
            return scoreRuleCheckInfo;
        }

        // 任务是否最近有执行出错的情况
        if(!checkAllSuccess(executeLogList)){
            scoreRuleCheckInfo.setScore(5);
            scoreRuleCheckInfo.setMsg(relationBO.getTaskName() + "：任务最近运行出错");
            return scoreRuleCheckInfo;
        }

        // 重要等级P2
        if("3".equals(lvl)){
            scoreRuleCheckInfo.setScore(3);
            scoreRuleCheckInfo.setMsg(relationBO.getTaskName() + "：重要级别为P2");
            return scoreRuleCheckInfo;
        }

/*
        // 任务更新时间 > 183d
        if(DateUtil.getDayBetweenDateTime(relationBO.getCreateTime(), relationBO.getUpdateTime()) > 183){
            scoreRuleCheckInfo.setScore(3);
            scoreRuleCheckInfo.setMsg(relationBO.getTaskName() + "：任务变更时间大于183天");
            return scoreRuleCheckInfo;
        }
*/
        if(!checkRunTime(executeLogList)){
            scoreRuleCheckInfo.setScore(3);
            scoreRuleCheckInfo.setMsg(relationBO.getTaskName() + "：任务运行时长波动较大");
            return scoreRuleCheckInfo;
        }

        // 上线时间小于7d
        if(DateUtil.getDayBetweenDateTime(relationBO.getCreateTime(), DateUtil.formatDateTime(System.currentTimeMillis())) < 7){
            scoreRuleCheckInfo.setScore(1);
            scoreRuleCheckInfo.setMsg(relationBO.getTaskName() + "：任务上线时间小于7天");
            return scoreRuleCheckInfo;
        }

        // 跨部门任务 判断在本部门任务表中是否有该任务信息
        if(!taskInfoMap.containsKey(relationBO.getTaskId())){
            scoreRuleCheckInfo.setScore(1);
            scoreRuleCheckInfo.setMsg(relationBO.getTaskName() + "：为外部门任务");
            return scoreRuleCheckInfo;
        }

        return scoreRuleCheckInfo;
    }

    /**
     * 校验根节点安全分
     * @param taskInfo
     * @return
     */
    private ScoreRuleCheckInfo checkRootTaskSecurityScore(TaskInfo taskInfo, Map<String, List<TaskExecuteLog>> logMap){
        ScoreRuleCheckInfo scoreRuleCheckInfo = new ScoreRuleCheckInfo();
        scoreRuleCheckInfo.setScore(0);
        String lvl = taskInfo.getImportantLvl();
        List<TaskExecuteLog> executeLogList = logMap.get(taskInfo.getTaskId());
        // 是否有配置重要级别
        if(Strings.isBlank(lvl) || "-1".equals(lvl)){
            scoreRuleCheckInfo.setScore(5);
            scoreRuleCheckInfo.setMsg(taskInfo.getTaskName() + "：未配置重要级别");
            return scoreRuleCheckInfo;
        }

        // 任务是否最近有执行出错的情况
        if(!checkAllSuccess(executeLogList)){
            scoreRuleCheckInfo.setScore(5);
            scoreRuleCheckInfo.setMsg(taskInfo.getTaskName() + "：任务最近运行出错");
            return scoreRuleCheckInfo;
        }

        // 重要等级P2
        if("3".equals(lvl)){
            scoreRuleCheckInfo.setScore(3);
            scoreRuleCheckInfo.setMsg(taskInfo.getTaskName() + "：重要级别为P2");
            return scoreRuleCheckInfo;
        }
/*

        // 任务更新时间 > 183d
        if(DateUtil.getDayBetweenDateTime(taskInfo.getCreateTime(), taskInfo.getUpdateTime()) > 183){
            scoreRuleCheckInfo.setScore(3);
            scoreRuleCheckInfo.setMsg(taskInfo.getTaskName() + "：任务变更时间大于183天");
            return scoreRuleCheckInfo;
        }
*/

        // 任务产出时间波动情况
        if(!checkRunTime(executeLogList)){
            scoreRuleCheckInfo.setScore(3);
            scoreRuleCheckInfo.setMsg(taskInfo.getTaskName() + "：任务运行时长波动较大");
            return scoreRuleCheckInfo;
        }

        // 上线时间小于7d
        if(DateUtil.getDayBetweenDateTime(taskInfo.getCreateTime(), DateUtil.formatDateTime(System.currentTimeMillis())) < 7){
            scoreRuleCheckInfo.setScore(1);
            scoreRuleCheckInfo.setMsg(taskInfo.getTaskName() + "：任务上线时间小于7天");
            return scoreRuleCheckInfo;
        }
        return scoreRuleCheckInfo;
    }

    /**
     * 查询任务
     * @param task
     * @return
     */
    private TaskInfo getTask(String task){
        TaskInfo taskInfo = taskInfoMapper.findByTaskId(task);
        if(taskInfo == null){
            taskInfo = taskInfoMapper.findByTaskName(task);
        }
        return taskInfo;
    }


    /**
     * 获取图下一层节点信息
     * @param taskId
     * @param type
     * @param parentPath
     * @param lvl
     * @param list
     * @param taskIdSet
     * @param relationMap
     * @param taskInfoMap
     */
    private void getNextLvlTask(String taskId, String type, String parentPath, int lvl, List<TaskRelationBO> list, Set<String> taskIdSet,
                                Map<String, List<TaskRelation>> relationMap, Map<String, TaskInfo> taskInfoMap){
        if(taskIdSet.contains(taskId)){
            return;
        }
        if(lvl > 0){
            taskIdSet.add(taskId);
            TaskRelationBO relationBO = new TaskRelationBO();
            relationBO.setTaskId(taskId);
            relationBO.setRelateType(type);
            relationBO.setPath(parentPath + "/" + taskId);
            relationBO.setLvl(lvl);

            TaskInfo taskInfo = taskInfoMap.get(taskId);
            if(taskInfo != null){
                fillTaskInfo(taskInfo, relationBO);
            }

            list.add(relationBO);
        }

        List<TaskRelation> taskRelations = relationMap.get(taskId);
        if(CollectionUtils.isEmpty(taskRelations)){
            return;
        }
        taskRelations.forEach(rel -> getNextLvlTask(rel.getRelateTaskId(), type, parentPath + "/" + rel.getTaskId(), lvl + 1,
                list, taskIdSet, relationMap, taskInfoMap));
    }

    /**
     * 填充外部门的任务
     * @param list
     */
    private void fillOtherDeptName(List<TaskRelationBO> list){
        List<String> taskIds = list.stream()
                .filter(rel -> Strings.isEmpty(rel.getTaskName()))
                .map(TaskRelationBO::getTaskId)
                .collect(Collectors.toList());
        List<TaskRelation> taskRelations = taskRelationService.findByTaskIds(taskIds);
        Map<String, TaskRelation> relationMap = taskRelations.stream()
                .collect(Collectors.toMap(TaskRelation::getTaskId, rel -> rel, (v1, v2) -> v2));

        list.forEach(bo -> {
            TaskRelation taskRelation = relationMap.get(bo.getTaskId());
            if(taskRelation == null){
                return;
            }
            bo.setTaskName(taskRelation.getTaskName());
            bo.setManager(taskRelation.getManager());
            bo.setImportantLvl(taskRelation.getImportantLvl());
            bo.setCreateTime(taskRelation.getCreateTime());
            bo.setUpdateTime(taskRelation.getUpdateTime());
            bo.setManageOrg("外部门");
        });
    }

    /**
     * 校验是否全部执行成功
     * @param logList
     * @return
     */
    private boolean checkAllSuccess(List<TaskExecuteLog> logList){
        if(CollectionUtils.isEmpty(logList)){
            return true;
        }
        for(TaskExecuteLog log: logList){
            if(400 != log.getJobState()){
                return false;
            }
        }
        return true;
    }

    /**
     * 校验是否有运行时间异常的
     * @param logList
     * @return
     */
    private boolean checkRunTime(List<TaskExecuteLog> logList){
        if(CollectionUtils.isEmpty(logList)){
            return true;
        }
        // 计算运行时间list
        List<Long> timeList = logList.stream()
                .map(log -> {
                    long startTime = DateUtil.parseDateTime(log.getExecuteStartTime());
                    long endTime = DateUtil.parseDateTime(log.getExecuteEndTime());
                    return endTime - startTime;
                }).collect(Collectors.toList());

        // 运行时间平均值
        double avgTime = timeList.stream().mapToLong(l -> l).average().orElse(0d);
        if(avgTime < 1000 * 60){
            return true;
        }
        // 平均时长超过1分钟，且差距超过50%的返回false
        for(Long time: timeList){
            if((time - avgTime)/ avgTime > 0.5){
                return false;
            }
        }
        // 结束时间 > 平均结束时间 + 运行时间，返回false
        double avgEndTime = logList.stream().mapToLong(log -> DateUtil.parseDateTime(log.getExecuteEndTime())).average().orElse(0d);
        for(TaskExecuteLog log: logList){
            long endTime = DateUtil.parseDateTime(log.getExecuteEndTime());
            if(endTime > avgEndTime + avgEndTime){
                return false;
            }
        }
        return true;
    }

    /**
     * 获取任务关联map
     * @param type
     * @return
     */
    private Map<String, List<TaskRelation>> getRelationMap(String type){
        List<TaskRelation> taskRelations = taskRelationService.findAllRelation();

        List<TaskRelation> filterList = taskRelations.stream()
                .filter(rel -> type.equals(rel.getRelationType()))
                .collect(Collectors.toList());
        return filterList.stream()
                .collect(Collectors.groupingBy(TaskRelation::getTaskId));
    }

    /**
     * 获取任务信息
     * @return
     */
    private Map<String, TaskInfo> getTaskInfoMap(){
        List<TaskInfo> taskInfos = taskInfoMapper.findAll();
        return taskInfos.stream()
                .collect(Collectors.toMap(TaskInfo::getTaskId, task -> task));
    }

    /**
     * 填充任务信息
     * @param taskInfo
     * @param taskRelationBO
     */
    private void fillTaskInfo(TaskInfo taskInfo, TaskRelationBO taskRelationBO){
        taskRelationBO.setTaskName(taskInfo.getTaskName());
        taskRelationBO.setManager(taskInfo.getManager());
        taskRelationBO.setCreateTime(taskInfo.getCreateTime());
        taskRelationBO.setUpdateTime(taskInfo.getUpdateTime());
        taskRelationBO.setImportantLvl(taskInfo.getImportantLvl());
        taskRelationBO.setManageOrg(taskInfo.getManageOrg());
    }
}
